package horde.internalResources.HorrorControl;

import horde.internalResources.dictionaries.dictionary;
import horde.internalResources.Directory;
import horde.internalResources.horrorControl.HCvis.horrorControlGraphics;
import horde.standard.resources.graphics.HFrame;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.util.ArrayList;
import javax.swing.JFrame;
import javax.swing.table.DefaultTableModel;

/**
 * Component that manages the treatment of all the platform events.
 * @author Arturo Mazón and Andres Picazo
 */
public class HorrorControl {

    // <editor-fold defaultstate="collapsed" desc="Trace Levels">
    public static final String TRACE_INFO = dictionary.getString("traceLevel.info");
    public static final String TRACE_DEBUG = dictionary.getString("traceLevel.debug");
    public static final String TRACE_WARNING = dictionary.getString("traceLevel.warning");
    public static final String TRACE_REMOTE = dictionary.getString("traceLevel.remote");
    public static final String ERROR_PLATFORM = dictionary.getString("errorLevel.platform");
    public static final String ERROR_APPLICATION = dictionary.getString("errorLevel.application");
    public static final String ERROR_JAVA = dictionary.getString("errorLevel.java");
    public static final String ERROR_COMUNICATION = dictionary.getString("errorLevel.comunication");
    // </editor-fold>

    // <editor-fold defaultstate="collapsed" desc="Keepers">
    /**
     * Storage of all the traces generated by the platform and each application
     */
    protected DefaultTableModel tracesKeeper; // ¿q campos?
    /**
     * Storage of all the exceptions captured by the platform and each application
     */
    protected DefaultTableModel exceptionKeeper; //¡!
    /**
     * Component wich purpose is storaging and treating the statistics of the whole platform
     */
    protected DefaultTableModel statistics;

    // </editor-fold>

    //Proccess and management of TRACES
    //Statitistics
    //TableModel to show traces in several formats
    //Proccess exceptions

    // <editor-fold defaultstate="collapsed" desc="Singleton">
    private HorrorControl() {
        locate("ES");
        try {
            tracesKeeper = new DefaultTableModel(null, fieldsTracesKeeper.toArray());
            statistics = new DefaultTableModel(null, fieldsStatistics.toArray());
            d = Directory.getInstance();
            vis = createGraphics();


        } catch (Exception e) {
        }
    }

    private HorrorControl(String s) {
        locate(s);
        try {
            tracesKeeper = new DefaultTableModel(null, fieldsTracesKeeper.toArray());
            statistics = new DefaultTableModel(null, fieldsStatistics.toArray());
            vis = createGraphics();
        } catch (Exception e) {
        }
    }

    /**
     *
     * @param d Directory d
     */
    @Deprecated
    private HorrorControl(Directory d) {
        locate("ES");
        try {
            tracesKeeper = new DefaultTableModel(null, fieldsTracesKeeper.toArray());
            statistics = new DefaultTableModel(null, fieldsStatistics.toArray());
//            vis = hcPanel.getInstance();
        } catch (Exception e) {
        }
        this.d = d;
    }

    private synchronized static void createInstance() {
        if (instance == null) {
            instance = new HorrorControl();
        }
    }

    @Deprecated
    private synchronized static void createInstance(Directory d) {
        if (instance == null) {
            instance = new HorrorControl(d);
        }
    }

    private synchronized static void createInstance(String s) {
        if (instance == null) {
            instance = new HorrorControl(s);
        }
    }

    public static HorrorControl getInstance() {
        if (instance == null) {
            createInstance();
        }
        return instance;
    }

    public static HorrorControl getInstance(String s) {
        if (instance == null) {
            createInstance(s);
        }
        return instance;
    }

    @Deprecated
    public static HorrorControl getInstance(Directory d) {
        if (instance == null) {
            createInstance(d);
        }
        return instance;
    }

    // </editor-fold>

    // <editor-fold defaultstate="collapsed" desc="Methods to trace">
    /**
     *
     * @param src Source of the trace
     * @param trace Message to show
     * @param trace_type Trace level
     */
    public void trace(String src, String trace, String trace_type) {
        try {
            String[] data = {src, trace, trace_type, "not specified"};
            tracesKeeper.addRow(data);
            vis.setJListModel(src);
            vis.addTrace(data);
        } catch (Exception e) {
//            String[] data = {nameHC,"Error tracing",ERROR_PLATFORM};
//            tracesKeeper.addRow(data);
            System.err.printf("%s->[%s:%s]%n", ERROR_PLATFORM, nameHC, "Error tracing");

        }
    }

    /**
     *
     * @param src Source of the trace
     * @param trace Message to show
     * @param trace_type Trace level
     * @param date Timestamp
     */
    public void trace(String src, String trace, String trace_type, String date) {
        try {
            String[] data = {src, trace, trace_type, date};
            tracesKeeper.addRow(data);
            vis.setJListModel(src);
            vis.addTrace(data);
        } catch (Exception e) {
//            String[] data = {nameHC,"Error tracing",ERROR_PLATFORM};
//            tracesKeeper.addRow(data);
            System.err.printf("%s->[%s:%s]%n", ERROR_PLATFORM, nameHC, "Error tracing");

        }
    }

    // </editor-fold>

    // <editor-fold defaultstate="collapsed" desc="Exports">
    /**
     *
     * @param flag Flag has possible values: File,Html,Xml,Console. 
     * File: A file named tracing.txt in the folder /logs is created with all the traces information.
     * Html:
     * Xml:
     * Console: All traces information is shown by console
     */
    public void export(String flag) {
        if (flag.equals("File")) {
            exportFile();
        } else if (flag.equals("Html")) {
            exportHtml();
        } else if (flag.equals("Xml")) {
            exportXml();
        } else if (flag.equals("Console")) {
            exportConsola();
        }
    }

    private void exportFile() {
        try {
            FileWriter fstream = new FileWriter(fileName);
            BufferedWriter out = new BufferedWriter(fstream);
            String format = "|%1$-20s|%2$-40s|%3$-10s|%4$-20s|";
            String separator = "";
            for (int k = 0; k < 95; k++) {
                separator += "-";
            }
            out.write(separator + "\n");
            out.write(String.format(format, "Source", "Message", "Level", "Timestamp") + "\n");
            out.write(separator + "\n");

            for (int i = 0; i < tracesKeeper.getRowCount(); i++) {//Filas


                String s = String.format(format, tracesKeeper.getValueAt(i, 0).toString(), tracesKeeper.getValueAt(i, 1).toString(),
                        tracesKeeper.getValueAt(i, 2).toString(), tracesKeeper.getValueAt(i, 3).toString());
                out.write(s);
                out.write("\n");
            }
            out.write(separator + "\n");
            out.close();
        } catch (Exception e) {
            System.err.println("Error: " + e.getMessage());
        }
    }

    private void exportHtml() {
        throw new UnsupportedOperationException("Not yet implemented");
    }

    private void exportXml() {
        throw new UnsupportedOperationException("Not yet implemented");
    }

    private void exportConsola() {
        System.out.println("Format: src/message/level : ");
        for (int i = 0; i < tracesKeeper.getRowCount(); i++) {
            System.out.println(tracesKeeper.getValueAt(i, 0).toString() + " "
                    + tracesKeeper.getValueAt(i, 1).toString() + "  "
                    + tracesKeeper.getValueAt(i, 2).toString() + "  ");
        }
    }
    /// </editor-fold>

    // <editor-fold defaultstate="collapsed" desc="Statistics">
    /**
     * Creates a DefaultTableModel named statistics with the agent ID, thread activity, pending task and number of resources associated to the agent (ID)
     */


    public void generateStatistics() {
        try {
            for (int i = 1; i < d.numberOfElements(); i++) {

                String id = d.getAgentID(i);
                ArrayList description = d.agentDescription(id);
                String[] data = {id, description.get(0).toString(), description.get(1).toString(), description.get(2).toString()};
                statistics.addRow(data);
            }
        } catch (Exception e) {
        }
    }
    // </editor-fold>

    public void locate(String s) {
        dictionary.setBundle(s);
        fieldsTracesKeeper.add("hc.field1TracesKeeper");
        fieldsTracesKeeper.add("hc.field2TracesKeeper");
        fieldsTracesKeeper.add("hc.field3TracesKeeper");
        fieldsTracesKeeper.add("hc.field4TracesKeeper");

        fieldsStatistics.add("hc.field1Statistics");
        fieldsStatistics.add("hc.field2Statistics");
        fieldsStatistics.add("hc.field3Statistics");
        fieldsStatistics.add("hc.field4Statistics");
    }

    /**
     * Obtains agents info from the directory
     * @return An array of all agents registered at the directory
     */
    public Object[] getAgents() {
        return d.getKeys().toArray();
    }

    // <editor-fold defaultstate="collapsed" desc="Graphics">
    /**
     * Creates the graphic interface for  the Horror Control
     * @return A representative object of the class horrorControlGraphics that extends JPanel
     */
    public horrorControlGraphics createGraphics() {
        return horrorControlGraphics.getInstance(this);
    }

    /**
     * Procedure that adds the name of a given agent to the list of agents of the graphic interface
     * @param src The name of the given agent
     */
    public void addAgentToVis(String src) {
        vis.addAgentToListModel(src);
    }

    /**
     * Creates a JFrame container of the HorrorControl's graphic interface
     * @return JFrame container of the HorrorControl's graphic interface
     */
    public static JFrame getFrameInstance() {
        if (hcf == null) {
            hcf = new HFrame("Horror Control", 600, 400, HorrorControl.getInstance().createGraphics());

        }
        return hcf;
    }

    /**
     * Static method that makes visible the graphic interface
     */
    public static void setVisibleFrame() {
        if (hcf != null) {
            hcf.setVisible(true);
        }
    }

    /**
     * Static method that indicates if the graphic interface is Shown
     * @return True if the frame is visible, false if not
     */
    public static boolean isShown() {
        return hcf != null;
    }
    // </editor-fold>

    // <editor-fold defaultstate="collapsed" desc="Atributes">
    private static HFrame hcf = null;
    private static HorrorControl instance = null;
    private static final String nameHC = dictionary.getString("hc.nameHC");
    private static final String fileName = dictionary.getString("hc.fileName");
    private ArrayList fieldsStatistics = new ArrayList();
    private ArrayList fieldsTracesKeeper = new ArrayList();
    private Directory d;
    private horrorControlGraphics vis = null;

    // </editor-fold>
}
